package com.example.micromallsearch.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.example.micromallsearch.bean.Person;
import com.example.micromallsearch.bean.Product;
import com.example.micromallsearch.bean.ProductES;
import com.fasterxml.jackson.databind.util.BeanUtil;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;


import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.IndicesClient;

import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
/*import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;*/
import org.elasticsearch.cluster.metadata.MappingMetaData;

import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//@SpringBootTest
@Service
public class ElasticsearchTests {

    @Autowired
    RestHighLevelClient client;



    /**
     * 根据id查询文档
     */
/*    public void getDoc() throws IOException {
        //设置查询的索引、文档
        GetRequest indexRequest=new GetRequest("product","1");
        GetResponse response = client.get(indexRequest, RequestOptions.DEFAULT);
        System.out.println(response.getSourceAsString());
    }*/

    /**
     *
     * @param index    索引
     * @param productES  存入的对象
     * @throws IOException
     */
    public void addDoc2(String index, ProductES productES) throws IOException {
        String data = JSON.toJSONString(productES);
        IndexRequest request=new IndexRequest(index).id(productES.getId().toString()).source(data, XContentType.JSON);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println(response.getId());
    }

    /**
     * 等值查询，即筛选出一个字段等于特定值的所有记录。 select * from person where name = '洗发*';
     * @throws IOException
     */

    public List<ProductES> queryTerm() throws IOException {

        HighlightBuilder highlightBuilder= new HighlightBuilder(); //生成高亮查询器
        highlightBuilder.field("洗发"); //高亮查询字段
        //highlightBuilder.field(content); //高亮查询字段
        //highlightBuilder.requireFieldMatch(false); //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags(""); //高亮设置
        highlightBuilder.postTags("");//下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        // 根据索引创建查询请求
        SearchRequest searchRequest = new SearchRequest("product");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建查询语句
        searchSourceBuilder.query(QueryBuilders.wildcardQuery("name","洗发*"));
        System.out.println("searchSourceBuilder=====================" + searchSourceBuilder);
        searchRequest.source(searchSourceBuilder);
        //response查询返回的json
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

        List<ProductES> productESList=new ArrayList<>();
        //解析该json
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(response.getHits()));
        JSONArray jsonArray = jsonObject.getJSONArray("hits");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            //获取需要的对象数据
            String sourceAsString = object.getString("sourceAsString");
            ProductES productES = JSON.parseObject(sourceAsString, ProductES.class);
            productESList.add(productES);
        }
        return productESList;
    }

    /**
     * 范围查询，即筛选出一个字段等于特定值的所有记录。 select * from pesons where age between 18 and 22;
     * @throws IOException
     */
    public List<ProductES> queryTerm2() throws IOException {
        // 根据索引创建查询请求
        SearchRequest searchRequest = new SearchRequest("product");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建查询语句
        searchSourceBuilder.query(QueryBuilders.rangeQuery("id").gte(1).lte(3));
        System.out.println("searchSourceBuilder=====================" + searchSourceBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        List<ProductES> productESList=new ArrayList<>();
        //解析该json
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(response.getHits()));
        JSONArray jsonArray = jsonObject.getJSONArray("hits");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            //获取需要的对象数据
            String sourceAsString = object.getString("sourceAsString");
            ProductES productES = JSON.parseObject(sourceAsString, ProductES.class);
            productESList.add(productES);
        }
        return productESList;
    }

    /**
     * 布尔查询
     * @throws IOException
     */
    public List<ProductES> queryTerm3(String keyword) throws IOException {
        // 根据索引创建查询请求
        SearchRequest searchRequest = new SearchRequest("product");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建查询语句  布尔查询
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                //must：所有的语句都必须匹配，与 ‘=’ 等价。
                //must_not：所有的语句都不能匹配，与 ‘!=’ 或 not in 等价。
                //.must(QueryBuilders.termQuery("sex", "女"))
                //should：至少有n个语句要匹配，n由参数控制。
                //.should(QueryBuilders.termQuery("address.word", "峨眉山"))
                //通配符查询-wildcard
                .should(QueryBuilders.wildcardQuery("id","*"+keyword+"*"))
                .should(QueryBuilders.wildcardQuery("name","*"+keyword+"*"))
                .should(QueryBuilders.wildcardQuery("description","*"+keyword+"*"))
                //范围查询-range
                //.should(QueryBuilders.rangeQuery("id").gte(1).lte(3))
                //数控制需要匹配的 should 语句的数量，它既可以是一个绝对的数字，又可以是个百分比：
                .minimumShouldMatch(1)
        );

        System.out.println("searchSourceBuilder=====================" + searchSourceBuilder);
        searchRequest.source(searchSourceBuilder);
        //response查询返回的json
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

        List<ProductES> productESList=new ArrayList<>();
        //解析该json
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(response.getHits()));
        JSONArray jsonArray = jsonObject.getJSONArray("hits");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            //获取需要的对象数据
            String sourceAsString = object.getString("sourceAsString");
            ProductES productES = JSON.parseObject(sourceAsString, ProductES.class);
            productESList.add(productES);
        }
        return productESList;
    }

    /**
     * 添加索引
     * @throws IOException
     */
    public void addIndex() throws IOException {
        //1.使用client获取操作索引对象
        IndicesClient indices = client.indices();
        //2.具体操作获取返回值
        //2.1 设置索引名称
        CreateIndexRequest createIndexRequest=new CreateIndexRequest("king1");
        CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        //3.根据返回值判断结果
        System.out.println(createIndexResponse.isAcknowledged());
    }

    /**
     * 添加索引，并添加映射
     */
    public void addIndexAndMapping() throws IOException {
        //1.使用client获取操作索引对象
        IndicesClient indices = client.indices();
        //2.具体操作获取返回值
        //2.具体操作，获取返回值
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("king");
        //2.1 设置mappings
        String mapping = "{\n" +
                "      \"properties\" : {\n" +
                "        \"address\" : {\n" +
                "          \"type\" : \"text\",\n" +
                "          \"analyzer\" : \"ik_max_word\"\n" +
                "        },\n" +
                "        \"age\" : {\n" +
                "          \"type\" : \"long\"\n" +
                "        },\n" +
                "        \"name\" : {\n" +
                "          \"type\" : \"keyword\"\n" +
                "        }\n" +
                "      }\n" +
                "    }";
        createIndexRequest.mapping(mapping, XContentType.JSON);

        CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        //3.根据返回值判断结果
        System.out.println(createIndexResponse.isAcknowledged());
    }

    /**
     * 查询索引  输出person==={1={properties={name={type=text, fields={keyword={ignore_above=256, type=keyword}}}}}}
     */
/*    public void queryIndex() throws IOException {
        IndicesClient indices = client.indices();
        GetIndexRequest getRequest=new GetIndexRequest("person");
        GetIndexResponse response = indices.get(getRequest, RequestOptions.DEFAULT);
        Map<String, MappingMetaData> mappings = response.getMappings();
        //iter 提示foreach
        for (String key : mappings.keySet()) {
            System.out.println(key+"==="+mappings.get(key).getSourceAsMap());
        }
    }*/

    /**
     * 删除索引
     */
    public void deleteIndex() throws IOException {
        IndicesClient indices = client.indices();
        DeleteIndexRequest deleteRequest=new DeleteIndexRequest("king1");
        AcknowledgedResponse delete = indices.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged());
    }

    /**
     * 索引是否存在
     */
/*    public void existIndex() throws IOException {
        IndicesClient indices = client.indices();
        GetIndexRequest getIndexRequest=new GetIndexRequest("king1");
        boolean exists = indices.exists(getIndexRequest, RequestOptions.DEFAULT);
        System.out.println(exists);
    }*/

    /**
     * 添加文档,使用map作为数据
     * @throws IOException
     */
    public void addDoc1() throws IOException {
        Map<String, Object> map=new HashMap<>();
        map.put("name","张三");
        map.put("age","18");
        map.put("address","北京二环");
        IndexRequest request=new IndexRequest("king").id("1").source(map);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println(response.getId());
    }



    /**
     * 修改文档：添加文档时，如果id存在则修改，id不存在则添加
     */
    public void UpdateDoc() throws IOException {
        Person person=new Person();
        person.setId("BPlEUH8BAXG1NsTOueH31");
        person.setName("李四");
        person.setAge(20);
        person.setAddress("北京三环车王1");
        String data = JSON.toJSONString(person);
        IndexRequest request=new IndexRequest("person2").id(person.getId()).source(data,XContentType.JSON);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println(response.getId());
    }


    /**
     * 根据id删除文档
     */
/*    public void delDoc() throws IOException {
        //设置要删除的索引、文档
        DeleteRequest deleteRequest=new DeleteRequest("king","1");
        DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(response.getId());
    }*/
}

